package com.huawang.mdesign.model.service.inter;

import com.huawang.business.command.definition.IAcrossCommand;
import com.huawang.business.command.definition.ICommand;
import com.huawang.business.command.executer.CommandExecutor;
import com.huawang.business.command.factory.CommandFactory;
import com.huawang.business.constants.ErrorCode;
import com.huawang.business.constants.ModelConstantURI;
import com.huawang.business.constants.ModelShareSeverityEnum;
import com.huawang.business.constants.ModelUsageSeverityEnum;
import com.huawang.business.data.share.core.IQueryShareService;
import com.huawang.business.data.share.core.ISaveShareService;
import com.huawang.business.data.share.entity.ShareElement;
import com.huawang.business.data.share.entity.UseElement;
import com.huawang.business.data.share.entity.UsePackage;
import com.huawang.business.data.share.entity.UseProject;
import com.huawang.business.dto.ModelPropertyInfo;
import com.huawang.business.dto.ProjectDTO;
import com.huawang.business.dto.graph.ModelInfo;
import com.huawang.business.dto.project.ModelDependency;
import com.huawang.business.dto.project.Project;
import com.huawang.business.dto.project.UsageProject;
import com.huawang.business.entity.share.*;
import com.huawang.business.exception.AbortExecutionException;
import com.huawang.business.service.cowork.ICoworkService;
import com.huawang.business.service.encapsulation.IEncapsulationService;
import com.huawang.business.service.init.IInitializeService;
import com.huawang.business.service.judge.BusinessJudgeService;
import com.huawang.business.service.model.base.Cache.NamingRuleCache;
import com.huawang.business.service.model.base.UmlService;
import com.huawang.business.service.model.core.*;
import com.huawang.business.service.model.core.project.InternalProjectService;
import com.huawang.business.service.model.core.project.ProjectManager;
import com.huawang.business.service.model.core.project.UsageProjectManager;
import com.huawang.business.service.modelusage.IModelUsageService;
import com.huawang.business.service.transaction.TransactionServiceImpl;
import com.huawang.business.util.CustomCollectionUtils;
import com.huawang.business.util.InstanceVoUtils;
import com.huawang.business.vo.ModelResultVo;
import com.huawang.core.definition.mof.UMLDefinitionConstants;
import com.huawang.core.definition.mof.cmof.reflection.impl.BasicRElement;
import com.huawang.core.definition.mof.instances.MetaClassInstance;
import com.huawang.core.mof.entity.slotValue.SlotValue;
import com.huawang.core.mof.persistence.constants.ShareType;
import com.huawang.core.mof.persistence.constants.UseType;
import com.huawang.core.semantics.entity.queryResult.MofResultContainer;
import com.huawang.core.semantics.entity.queryResult.QueryPropertyForm;
import com.huawang.core.semantics.entity.transaction.LocalTransaction;
import com.huawang.core.semantics.exception.CommandException;
import com.huawang.core.semantics.exception.LocalTransactionNotStartException;
import com.huawang.core.semantics.exception.TransactionNotExistingException;
import com.huawang.core.semantics.service.save.ISaveInstanceService;
import com.huawang.mdesign.model.service.dto.ProjectOpenDTO;
import com.huawang.mdesign.model.service.dto.share.*;
import com.huawang.mdesign.model.service.util.LogUtil;
import com.huawang.mdesign.model.service.vo.IllegalVo;
import com.huawang.mdesign.model.service.vo.UseElementGroupVo;
import com.huawang.mdesign.model.service.vo.ValidatorAnnoation;
import com.huawang.mdesign.model.service.vo.ValidatorResultVo;
import com.huawang.mdesign.model.service.vo.share.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.huawang.business.constants.ModelActionName.PROJECT_PRIVATIZATION;
import static com.huawang.business.constants.ModelActionName.PROJECT_USAGE;
import static com.huawang.business.constants.ProfileConstants.DEFAULT_PROFILE;

@Slf4j
@Service
@Primary
public class ProjectShareService {

    @Autowired
    private ProjectService projectService;

    @Autowired
    private ProjectManager projectManager;

    @Autowired
    private UsageProjectManager usageProjectManager;

    @Autowired
    private InternalUmlService internalUmlService;

    @Autowired
    private InternalProjectService internalProjectService;

    @Autowired
    private InternalModelIconService internalModelIconService;

    @Autowired
    private InternalPropertyService internalPropertyService;

    @Autowired
    private ValidationService validationService;

    @Autowired
    private InternalDiagramService internalDiagramService;

    @Autowired
    private ModelPropertyInfoService modelPropertyInfoService;

    @Autowired
    private TransactionServiceImpl transactionService;

    @Autowired
    private IModelUsageService modelUsageService;

    @Autowired
    private CommandExecutor commandExecutor;

    @Autowired
    private IEncapsulationService encapsulationService;

    @Autowired
    private ICoworkService coworkService;

    @Autowired
    private IQueryShareService queryShareService;

    @Autowired
    private IInitializeService initializeService;

    @Autowired
    private UmlService umlService;

    @Autowired
    private ISaveShareService saveShareService;

    @Autowired
    private ISaveInstanceService iSaveInstanceService;

    @Autowired
    private NamingRuleCache namingRuleCache;

    protected static final Map<String, String> saveAsProjectMap = new HashMap<>();

    @NotNull
    public ConfirmShareResultVo confirmPackage(ProjectShareDTO dto) {
        LogUtil.printSerializeOnlineLogs("confirmPackage -> dto: ", dto);
        final String projectId = dto.getProjectId();
        List<ShareHangLocation> sharingPackage = modelUsageService.querySharingPackages(dto.getProjectId());
        List<String> oldSharingPackageIds = sharingPackage.stream().map(ShareHangLocation::getInstanceId).collect(Collectors.toList());
        Set<String> newPackageIds = dto.getSharePackages().stream().map(UsagePackageVo::getInstanceId).collect(Collectors.toSet());

        final List<String> encryptIdList = encapsulationService.queryAllEncryptInstanceIds(projectId);
        if (Boolean.TRUE.equals(internalUmlService.isTargetParent(projectId, new ArrayList<>(newPackageIds), encryptIdList))) {
            log.error("共享包下存在封装模型");
            throw AbortExecutionException.build(ErrorCode.CONTAIN_ENCRYPTEDMODEL_ERROR);
        }
        if (Boolean.TRUE.equals(internalUmlService.isTargetParent(projectId, encryptIdList, new ArrayList<>(newPackageIds)))) {
            log.error("共享包被封装模型所包含");
            throw AbortExecutionException.build(ErrorCode.CONTAINED_BY_ENCRYPTEDMODEL_ERROR);
        }
        List<String> childrenIds = internalUmlService.getChildrenCascadeIds(projectId, new ArrayList<>(newPackageIds), false);
        List<MetaClassInstance> childrenList = internalUmlService.fetchInstanceByIds(childrenIds, projectId);
        Map<String, Set<String>> givenTypes = internalUmlService.getGivenTypes(projectId, childrenList);
        Optional<String> dataMappingOptional = childrenList.stream().map(BasicRElement::getId)
                .filter(id -> givenTypes.get(id).contains(UMLDefinitionConstants.Customization_DataMapping)).findFirst();
        if (dataMappingOptional.isPresent()) {
            log.error("共享包下存在DataMapping！");
            throw AbortExecutionException.build(ErrorCode.CONTAIN_DATA_MAPPING_ERROR);
        }

        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        final ConfirmShareResultVo resultVo = new ConfirmShareResultVo();
        try {
            //0.查询当前已共享的包
            //1.比较新增的包，删除的包
            List<Set<String>> result = CustomCollectionUtils.getUnionOfList(sharingPackage.stream().map(ShareHangLocation::getInstanceId).collect(Collectors.toSet()),
                    newPackageIds);
            Set<String> deletePackageIds = result.get(0);
            Set<String> addPackageIds = result.get(2);
            List<ICommand> commands = new ArrayList<>();
            //2.删除包
            if (CollectionUtils.isNotEmpty(deletePackageIds)) {
                commands.add(CommandFactory.createDeleteSharePackageCommand(dto.getProjectId(),
                        new ArrayList<>(deletePackageIds)));
            }

            //3.新增包
            if (CollectionUtils.isNotEmpty(addPackageIds)) {
                List<ShareHangLocation> addPackages = dto.getSharePackages().stream().filter(it -> addPackageIds.contains(it.getInstanceId()))
                        .map(it -> new ShareHangLocation(it.getInstanceId(), it.getExpectParent(), null, null))
                        .collect(Collectors.toList());
                commands.add(CommandFactory.createAddSharePackageCommand(dto.getProjectId(),
                        addPackages, dto.getDiagramModelIds()));
            }

            commands.add(CommandFactory.createAutoShareCommand(dto.getDiagramModelIds()));
            commandExecutor.executes(dto.getProjectId(), commands);
            //5.查询更新后的共享包，并返回比较结果

            List<ShareHangLocation> newSharingPackages =
                    modelUsageService.querySharingPackages(dto.getProjectId());
            List<String> newSharingPackageIds = newSharingPackages.stream().map(ShareHangLocation::getInstanceId)
                    .collect(Collectors.toList());
            resultVo.setSharePackages(newSharingPackageIds.stream()
                    .filter(it -> !oldSharingPackageIds.contains(it))
                    .collect(Collectors.toList()));
            oldSharingPackageIds.removeAll(newSharingPackageIds);
            resultVo.setDeletePackages(oldSharingPackageIds);
            transactionService.commit(projectId);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROJECT_SHARE_ERROR, e);
        }

        return resultVo;
    }

    @NotNull
    public List<ValidatorResultVo> queryShareResult(String projectId, List<MetaClassInstance> elements) {
        LogUtil.printOnlineLogs("queryShareResult -> projectId: ", projectId);
        ShareWarning sharingWarning = modelUsageService.getShareWarning(projectId, elements);
        List<String> exceptionPropertyIds = sharingWarning.getExceptionPropertyWarningMap().values().stream()
                .map(PropertyWarning::getOwningInstanceId).distinct().collect(Collectors.toList());
        //stereotype属性查询
        Map<String, List<SlotValue>> slotValueVos = internalUmlService.querySlotValueVOByMemberIds(projectId,
                sharingWarning.getExceptionPropertyWarningMap().values().stream().map(it -> it.getValues().getId()).collect(Collectors.toList()));
        Map<String, ModelPropertyInfo> exceptionInstances = modelPropertyInfoService.createModelPropertyInfoList(projectId,
                        internalUmlService.fetchInstanceByIds(exceptionPropertyIds, projectId),
                        Stream.of(UMLDefinitionConstants.NamedElement_qualifiedName).collect(Collectors.toList()))
                .stream().collect(Collectors.toMap(it -> it.getInstance().getId(), it -> it));
        final Map<String, MetaClassInstance> instanceMap = this.internalUmlService.fetchInstances(
                Stream.concat(slotValueVos.keySet().stream(), slotValueVos.values().stream().flatMap(Collection::stream).
                        map(SlotValue::getValueSpecificationId)).distinct().collect(Collectors.toList()), projectId);
        //uml属性处理
        Map<String, List<ValidatorAnnoation>> validatorAnnoation = sharingWarning.getExceptionPropertyWarningMap().entrySet().stream().map(it -> {
            ModelPropertyInfo modelInfo = exceptionInstances.get(it.getValue().getOwningInstanceId());
            if (modelInfo == null) {
                return null;
            }

            if (slotValueVos.containsKey(modelInfo.getInstanceId())) {
                List<SlotValue> slots = slotValueVos.get(modelInfo.getInstanceId());
                if (CollectionUtils.isEmpty(slots)) {
                    return null;
                }

                SlotValue slot = slots.get(0);
                ShareValidatorAnnoation annoation = new ShareValidatorAnnoation();
                annoation.setSeverity(ModelShareSeverityEnum.IMPORT_NOT_SHARE_MODEL.getSeverity().value());
                annoation.setErrorType(ModelShareSeverityEnum.IMPORT_NOT_SHARE_MODEL.getErrorType());
                annoation.setAbbreviation(ModelShareSeverityEnum.IMPORT_NOT_SHARE_MODEL.abbreviation());
                annoation.setErrorMessage(createErrorMessage(projectId, instanceMap.get(slot.getOwningInstanceId()),
                        slot.getPropertyName(),
                        instanceMap.get(slot.getValueSpecificationId())));
                annoation.setWarningModelInfo(createWarningModelInfo(slot));
                annoation.setInstanceId(slot.getOwningInstanceId());
                annoation.setIgnore(it.getValue().getIsIgnored());
                annoation.setWarningId(it.getKey());
                return annoation;
            } else {
                ShareValidatorAnnoation annoation = new ShareValidatorAnnoation();
                annoation.setSeverity(ModelShareSeverityEnum.IMPORT_NOT_SHARE_MODEL.getSeverity().value());
                annoation.setErrorType(ModelShareSeverityEnum.IMPORT_NOT_SHARE_MODEL.getErrorType());
                annoation.setAbbreviation(ModelShareSeverityEnum.IMPORT_NOT_SHARE_MODEL.abbreviation());
                annoation.setErrorMessage(createErrorMessage(projectId, modelInfo.getInstance(),
                        it.getValue().getPropertyName(), it.getValue().getValues()));
                annoation.setWarningModelInfo(createWarningModelInfo(it.getValue()));
                annoation.setInstanceId(modelInfo.getInstance().getId());
                annoation.setIgnore(it.getValue().getIsIgnored());
                annoation.setWarningId(it.getKey());
                return annoation;
            }

        }).filter(Objects::nonNull).collect(Collectors.groupingBy(ValidatorAnnoation::getInstanceId));


        Map<String, ValidatorResultVo> resultVos = generateValidatorResultMapByValidatorAnnotation(projectId, validatorAnnoation);

        final QueryPropertyForm form = new QueryPropertyForm();
        form.add(sharingWarning.getExceptionOwners(), UMLDefinitionConstants.NamedElement_qualifiedName);
        final MofResultContainer container = internalUmlService.queryProperty(projectId, form);

        addResultVo(projectId, sharingWarning.getExceptionOwners(), resultVos, container);

        return new ArrayList<>(resultVos.values());
    }

    private static void addResultVo(String projectId, List<MetaClassInstance> exceptionOwners, Map<String, ValidatorResultVo> resultVos, MofResultContainer container) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, exceptionOwners: {}", projectId, exceptionOwners);
        exceptionOwners.forEach(it -> {
            ValidatorResultVo vo;
            if (resultVos.containsKey(it.getId())) {
                vo = resultVos.get(it.getId());
            } else {
                vo = new ValidatorResultVo();
                vo.setInstanceId(it.getId());
                vo.setNamespace(container.queryStringProperty(it.getId(), UMLDefinitionConstants.NamedElement_qualifiedName));
                vo.setAnnoations(new ArrayList<>());
                resultVos.put(it.getId(), vo);
            }

            ValidatorAnnoation annoation = new ValidatorAnnoation();
            annoation.setWarningId(ModelConstantURI.initInstanceId());
            annoation.setSeverity(ModelShareSeverityEnum.CHILD_ERROR.getSeverity().value());
            annoation.setErrorType(ModelShareSeverityEnum.CHILD_ERROR.getErrorType());
            annoation.setAbbreviation(ModelShareSeverityEnum.CHILD_ERROR.abbreviation());
            annoation.setErrorMessage(ModelShareSeverityEnum.CHILD_ERROR.errorMessage());
            vo.setOwnerId(it.getOwnerId());
            vo.getAnnoations().add(annoation);
        });
    }

    @NotNull
    private Map<String, ValidatorResultVo> generateValidatorResultMapByValidatorAnnotation(String projectId,
                                                                                           Map<String, List<ValidatorAnnoation>> validatorAnnotation) {
        LogUtil.printOnlineLogs("generateValidatorResultMapByValidatorAnnotation -> projectId: ", projectId);
        Map<String, ValidatorResultVo> resultVos = new HashMap<>(validatorAnnotation.size());
        final Map<String, MetaClassInstance> instanceMap = internalUmlService.fetchInstances(new ArrayList<>(resultVos.keySet()), projectId);
        final QueryPropertyForm form = new QueryPropertyForm();
        form.add(new ArrayList<>(instanceMap.values()), UMLDefinitionConstants.NamedElement_qualifiedName);
        final MofResultContainer container = internalUmlService.queryProperty(projectId, form);
        validatorAnnotation.forEach((key, value) -> {
            ValidatorResultVo vo = new ValidatorResultVo();
            vo.setInstanceId(key);
            vo.setNamespace(container.queryStringProperty(key, UMLDefinitionConstants.NamedElement_qualifiedName));
            vo.setAnnoations(value);
            resultVos.put(key, vo);
        });
        return resultVos;
    }

    @NotNull
    private static WarningModelInfo createWarningModelInfo(PropertyWarning errorProperty) {
        LogUtil.printSerializeOnlineLogs("errorProperty: ", errorProperty);
        WarningModelInfo warningModelInfo = new WarningModelInfo();
        warningModelInfo.setPropertyKey(errorProperty.getPropertyName());
        warningModelInfo.setValue(errorProperty.getValues().getId());
        return warningModelInfo;
    }

    @NotNull
    private static WarningModelInfo createWarningModelInfo(SlotValue slotValueVO) {
        LogUtil.printSerializeOnlineLogs("slotValueVO: ", slotValueVO);
        WarningModelInfo warningModelInfo = new WarningModelInfo();
        warningModelInfo.setPropertyKey(slotValueVO.getPropertyName());
        warningModelInfo.setValue(slotValueVO.getValueSpecificationId());
        return warningModelInfo;
    }

    @NotNull
    private String createErrorMessage(String projectId, MetaClassInstance instance, String propertyName,
                                      MetaClassInstance value) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, instance: {}, propertyName: {}, value: {}", projectId, instance,
                propertyName, value);
        if (instance == null) {
            return "";
        }
        final String messageFormat = "该%s的%s属性引用了\"%s %s\"，该元素未共享";
        ModelInfo modelInfo = internalUmlService.fetchModelInfoValue(projectId, instance);
        String modelTypeName = "";
        if (modelInfo != null) {
            modelTypeName = modelInfo.getCnName();
        }

        final String propertyCnName = internalPropertyService.queryPropertyCnName(propertyName);

        final String valueName = internalUmlService.queryStringProperty(projectId, value,
                UMLDefinitionConstants.NamedElement_name);
        final ModelInfo info = internalUmlService.fetchModelInfoValue(projectId, value);
        final String cnName = info == null ? "" : info.getCnName();
        return String.format(messageFormat, modelTypeName, propertyCnName, cnName, valueName == null ?
                "" : valueName);
    }

    @NotNull
    public ModelResultVo confirmUsageProject(ProjectUsageDTO dto) {
        LogUtil.printSerializeOnlineLogs("confirmUsageProject -> dto: ", dto);
        final UsageProject usageProject = usageProjectManager.getProject(dto.getShareProjectId());
        if (usageProject == null) {
            throw AbortExecutionException.build(ErrorCode.SHARE_PROJECT_NOT_EXIST);
        }
        //2.使用项目
        final String projectId = dto.getProjectId();
        // 设置默认挂载路径
        beforeHandle(projectId, dto);
        Project project = projectManager.getValidProject(dto.getProjectId());
        ProjectDescription projectDescription = new ProjectDescription("", project.getId(), "", project.getId(),
                project.getVersion());
        ProjectDescription usageProjectDescription = new ProjectDescription(usageProject.getProjectPath(),
                usageProject.getOrignalProjectId(), usageProject.getProjectName(), usageProject.getId(), usageProject.getVersion());
        final Map<String, MetaClassInstance> instanceMap = internalUmlService.fetchInstances(
                dto.getUsagePackageParent().stream().map(UsagePackageVo::getInstanceId).collect(Collectors.toList()), dto.getShareProjectId());
        List<ShareHangLocation> addPackages = dto.getUsagePackageParent().stream().filter(it -> {
                    MetaClassInstance p = instanceMap.get(it.getInstanceId());
                    if (p == null) {
                        return false;
                    }

                    return !internalUmlService.checkInstanceType(projectId, p,
                            UMLDefinitionConstants.Profile) || BusinessJudgeService.isCreatedInteractive(p);
                }).map(it -> new ShareHangLocation(it.getInstanceId(), Objects.isNull(it.getExpectParent()) ? "" : it.getExpectParent(),
                        Objects.isNull(it.getUsedParent()) ? "" : it.getUsedParent(), null))
                .collect(Collectors.toList());
        IAcrossCommand command = CommandFactory.createUseProjectCommand(projectDescription, usageProjectDescription,
                addPackages, dto.getDiagramModelIds());
        final QueryPropertyForm form = new QueryPropertyForm();
        form.add(new ArrayList<>(instanceMap.values()), UMLDefinitionConstants.NamedElement_name);
        final MofResultContainer container = internalUmlService.queryProperty(usageProject.getId(), form);
        List<ICommand> updateCommands = addPackages.stream().map(it -> {
            MetaClassInstance usePackage = instanceMap.get(it.getInstanceId());
            if (usePackage != null) {
                String name = container.queryStringProperty(it.getInstanceId(), UMLDefinitionConstants.NamedElement_name);
                String icon = internalModelIconService.queryIcon(usageProject.getId(), usePackage);
                return CommandFactory.createUpdateUsePackageCommand(it.getInstanceId(), name, icon);
            }

            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());
        ICommand promptUpdateCommand = CommandFactory.createUpdateUseProjectCommand(usageProject.getOrignalProjectId(),
                usageProject.getOrignalProjectId(), usageProject.getProjectPath(), usageProject.getProjectName(),
                usageProject.getVersion(),
                BooleanUtils.isTrue(dto.getPromptUpdate()) ? 1 : 0);
        ModelResultVo modelResultVo = new ModelResultVo();

        List<ICommand> updateUsageOwnerCommands = createUpdateUsageOwnerCommand(projectId, dto.getUsagePackageParent());
        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        try {
            commandExecutor.executesAcrossDataSource(command);
            commandExecutor.executes(projectId, updateCommands);
            // 更新使用项目Owner
            internalProjectService.setGlobalWriteableState(projectId, true);
            commandExecutor.executes(projectId, updateUsageOwnerCommands);
            internalProjectService.setGlobalWriteableState(projectId, false);
            commandExecutor.executes(projectId, Stream.of(promptUpdateCommand).collect(Collectors.toList()));
            projectService.loadPrivateData(projectId, project.getProjectSpecification());
            transactionService.commit(projectId);
            InstanceVoUtils.fillAddModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }

        return modelResultVo;
    }

    /**
     * description:模型下发使用项目
     */
    public ModelResultVo distributeConfirmUsageProject(ProjectDistributeDTO dto) {
        //1.使用项目
        final Project usageProject = projectManager.getValidProject(dto.getShareProjectId());
        //2.主项目
        final String projectId = dto.getProjectId();
        Project project = projectManager.getValidProject(dto.getProjectId());
        com.huawang.business.data.share.entity.Project projectEntity = new com.huawang.business.data.share.entity.Project(
                project.getId(), "", "");
        com.huawang.business.data.share.entity.Project usageProjectEntity = new com.huawang.business.data.share.entity.Project(
                usageProject.getId(), usageProject.getPath(), usageProject.getName());
        MetaClassInstance distributePackage = internalUmlService.fetchInstance(dto.getDistributePackageId(), projectId);
        if (distributePackage == null) {
            log.error("下发使用项目为空");
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR);
        }

        ModelResultVo modelResultVo = new ModelResultVo();
        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        try {
            String icon = internalModelIconService.queryIcon(usageProject.getId(), distributePackage);
            String name = internalUmlService.queryStringProperty(projectId, distributePackage, UMLDefinitionConstants.NamedElement_name);
            modelUsageService.changeElementToUseElement(projectEntity, usageProjectEntity, distributePackage.getId(), icon == null ? "" : icon, name == null ? "" : name, distributePackage.getOwnerId());
            transactionService.commit(projectId);
            InstanceVoUtils.fillAddModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }

        return modelResultVo;
    }

    private void beforeHandle(String projectId, ProjectUsageDTO dto) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, dto: {}", projectId, dto);
        // 未选的挂载节点将其置为根节点
        final String rootModel = projectManager.getValidProject(projectId).getRootModel();
        dto.getUsagePackageParent().forEach(it -> {
            if (StringUtils.isEmpty(it.getUsedParent())) {
                it.setUsedParent(rootModel);
            }
        });
    }

    /**
     * description:更新使用项目的挂载路径
     */
    @NotNull
    public ModelResultVo updateUsageOwner(UpdateUsageOwnerDTO updateUsageOwnerDTO) {
        LogUtil.printSerializeOnlineLogs("updateUsageOwnerDTO: ", updateUsageOwnerDTO);
        final String projectId = updateUsageOwnerDTO.getProjectId();
        final UsagePackageVo usagePackageVo = updateUsageOwnerDTO.getUsagePackageParent();
        List<ICommand> updateUsageOwnerCommands = createUpdateUsageOwnerCommand(projectId, Collections.singletonList(usagePackageVo));

        ModelResultVo modelResultVo = new ModelResultVo();
        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        try {
            List<UsePackage> usePackages = queryShareService.queryUsePackageByUsePackageIds(projectId, Collections.singletonList(usagePackageVo.getInstanceId()));
            if (CollectionUtils.isEmpty(usePackages)) {
                throw new UnsupportedOperationException("包不存在");
            }
            internalProjectService.setGlobalWriteableState(projectId, true);
            List<UsePackage> updateUsePackage = usePackages.stream().map(usePackage -> {
                if (!StringUtils.equals(usagePackageVo.getUsedParent(), usePackage.getExpectedHangLocation())) {
                    usePackage.setConfigurationHangLocation(usagePackageVo.getUsedParent());
                    return usePackage;
                }
                return null;
            }).filter(Objects::nonNull).collect(Collectors.toList());
            saveShareService.updateUsePackages(projectId, updateUsePackage);
            commandExecutor.executes(projectId, updateUsageOwnerCommands);
            internalProjectService.setGlobalWriteableState(projectId, false);
            transactionService.commit(projectId);
            InstanceVoUtils.fillAddModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }

        return modelResultVo;
    }

    @NotNull
    private List<ICommand> createUpdateUsageOwnerCommand(@NotNull String projectId,
                                                         @NotNull List<UsagePackageVo> usagePackageVos) {
        LogUtil.printSerializeOnlineLogs("updateUsageOwnerDTO: ", projectId, usagePackageVos);
        Map<String, MetaClassInstance> parentInstanceMap = internalUmlService.fetchInstances(
                usagePackageVos.stream().map(UsagePackageVo::getUsedParent).filter(Objects::nonNull).collect(Collectors.toList()),
                projectId);
        return usagePackageVos.stream().map(usagePackageVo -> {
            final String parentId = usagePackageVo.getUsedParent();
            final String instanceId = usagePackageVo.getInstanceId();
            return parentId != null ?
                    umlService.createUpdateCommand(projectId, instanceId, UMLDefinitionConstants.Element_owner, parentInstanceMap.get(parentId)) :
                    null;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 打开使用项目
     *
     * @return com.huawang.mdesign.model.service.model.project.Project
     * @author xz
     * @date 2023/02/21 10:57r
     */
    @NotNull
    public UsageProject openUsageProject(ProjectOpenDTO dto) {
        LogUtil.printSerializeOnlineLogs("openUsageProject -> dto: ", dto);
        //1.打开使用项目，增加数据源
        ProjectDTO projectDto = projectService.makeProjectDto(dto);

        if (StringUtils.isEmpty(projectDto.getDataSourceId())) {
            log.error("打开使用项目失败, dataSourceId为空");
            throw AbortExecutionException.build(ErrorCode.SHARE_PROJECT_NOT_EXIST);
        }

        UsageProject usageProject = usageProjectManager.getProject(projectDto.getDataSourceId());
        if (usageProject != null) {
            return usageProject;
        }

        //1.1加载profile和缓存
        usageProject = usageProjectManager.active(projectDto.getFilePath(),
                projectDto.getProjectId(), projectDto.getName(),
                projectDto.getDependencies(), dto.getDefaultSaveDir(), projectDto.getDataSourceId(), projectDto.getSpecification());
        usageProject.setRootModel(projectDto.getRootModel());
        usageProject.setVersion(projectDto.getVersion());
        usageProject.setOnline(projectDto.isOnline());
        final List<ModelDependency> initProfile = DEFAULT_PROFILE.stream().map(it ->
                new ModelDependency(it, 1L)).collect(Collectors.toList());
        Set<String> profileIds;
        try {
            if (usageProject.isOnline()) {
                profileIds = projectService.initProfileDependency(projectDto.getDependencies(),
                        projectDto.getOnlineProfileLibPath(),
                        initProfile, projectDto.getProfileLibPath(), usageProject);
                this.initializeService.initialize(usageProject.getId(), false, true, true, usageProject.getProjectSpecification());
                MetaClassInstance rootModel = internalUmlService.fetchInstance(usageProject.getRootModel(), usageProject.getId());
                internalProjectService.setProfileOwner(usageProject, rootModel, profileIds);
            } else {
                this.initializeService.initialize(usageProject.getId(), false, true, true, usageProject.getProjectSpecification());
            }
        } catch (Exception e) {
            usageProjectManager.clear(usageProject.getId());
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }

        coworkService.updateAllPackageIsReadOnlyOrNot(usageProject.getId(), true);
        return usageProject;
    }

    @NotNull
    public List<ValidatorResultVo> queryUsageResult(String projectId) {
        LogUtil.printSerializeOnlineLogs("queryUsageResult -> projectId: ", projectId);
        UseWarning usingWarnings = modelUsageService.getUseWarning(projectId);
        List<String> exceptionPropertyIds =
                usingWarnings.getExceptionPropertyWarningMap().values().stream().map(PropertyWarning::getOwningInstanceId).distinct()
                        .collect(Collectors.toList());
        //stereotype属性查询
        Map<String, List<SlotValue>> slotValueVos = internalUmlService.querySlotValueVOByMemberIds(projectId,
                exceptionPropertyIds);

        final Map<String, MetaClassInstance> instanceMap = internalUmlService.fetchInstances(
                usingWarnings.getExceptionPropertyWarningMap().values().stream().map(PropertyWarning::getOwningInstanceId)
                        .collect(Collectors.toList()), projectId);
        Map<String, List<ValidatorAnnoation>> validatorAnnoation = usingWarnings.getExceptionPropertyWarningMap().entrySet()
                .stream()
                .map(it -> {
                    MetaClassInstance instance = instanceMap.get(it.getValue().getOwningInstanceId());
                    if (instance == null) {
                        return null;
                    }

                    if (slotValueVos.containsKey(instance.getId())) {
                        List<SlotValue> slots = slotValueVos.get(instance.getId());
                        if (CollectionUtils.isEmpty(slots)) {
                            return null;
                        }

                        SlotValue slot = slots.get(0);
                        ShareValidatorAnnoation annoation = new ShareValidatorAnnoation();
                        annoation.setSeverity(ModelUsageSeverityEnum.IMPORT_RESUME.getSeverity().value());
                        annoation.setErrorType(ModelUsageSeverityEnum.IMPORT_RESUME.getErrorType());
                        annoation.setAbbreviation(ModelUsageSeverityEnum.IMPORT_RESUME.abbreviation());
                        annoation.setErrorMessage(createErrorMessage(projectId, instance,
                                slot.getPropertyName(), it.getValue().getValues()));
                        annoation.setWarningModelInfo(createWarningModelInfo(slot));
                        annoation.setInstanceId(slot.getOwningInstanceId());
                        annoation.setIgnore(it.getValue().getIsIgnored());
                        annoation.setWarningId(it.getKey());
                        return annoation;
                    } else {
                        ShareValidatorAnnoation annoation = new ShareValidatorAnnoation();
                        annoation.setSeverity(ModelUsageSeverityEnum.IMPORT_RESUME.getSeverity().value());
                        annoation.setErrorType(ModelUsageSeverityEnum.IMPORT_RESUME.getErrorType());
                        annoation.setAbbreviation(ModelUsageSeverityEnum.IMPORT_RESUME.abbreviation());
                        annoation.setErrorMessage(createErrorMessage(projectId, instance,
                                it.getValue().getPropertyName(), it.getValue().getValues()));
                        annoation.setWarningModelInfo(createWarningModelInfo(it.getValue()));
                        annoation.setInstanceId(instance.getId());
                        annoation.setIgnore(it.getValue().getIsIgnored());
                        annoation.setWarningId(it.getKey());
                        return annoation;
                    }

                }).filter(Objects::nonNull).collect(Collectors.groupingBy(ValidatorAnnoation::getInstanceId));

        Map<String, ValidatorResultVo> resultVos = generateValidatorResultMapByValidatorAnnotation(projectId, validatorAnnoation);
        final Map<String, InstanceWarning> recoveryInstances = usingWarnings.getRecoveryInstances();
        final Map<String, InstanceWarning> proxyInstances = usingWarnings.getProxyInstances();
        final QueryPropertyForm form = new QueryPropertyForm();
        form.add(usingWarnings.getExceptionOwners(), UMLDefinitionConstants.NamedElement_qualifiedName);
        form.add(Stream.concat(recoveryInstances.values().stream().map(InstanceWarning::getMetaClassInstance),
                        proxyInstances.values().stream().map(InstanceWarning::getMetaClassInstance))
                .collect(Collectors.toList()), UMLDefinitionConstants.NamedElement_qualifiedName);
        final MofResultContainer container = internalUmlService.queryProperty(projectId, form);
        addResultVo(projectId, usingWarnings.getExceptionOwners(), resultVos, container);

        recoveryInstances.forEach((ignoreId, instanceWarning) -> createOrUpdateValidatorResult(ignoreId, instanceWarning, resultVos, ModelUsageSeverityEnum.RESUME, container));

        proxyInstances.forEach((ignoreId, instanceWarning) -> createOrUpdateValidatorResult(ignoreId, instanceWarning, resultVos, ModelUsageSeverityEnum.MISSING, container));

        return new ArrayList<>(resultVos.values());
    }

    private static void createOrUpdateValidatorResult(String ignoreId, InstanceWarning instanceWarning,
                                                      Map<String, ValidatorResultVo> resultVos, ModelUsageSeverityEnum modelUsageSeverityEnum,
                                                      MofResultContainer container) {
        LogUtil.printSerializeOnlineLogs("ignoreId: {}, instanceWarning: {},  resultVos: {}, modelUsageSeverityEnum: {}",
                ignoreId, instanceWarning, resultVos, modelUsageSeverityEnum);
        ValidatorResultVo vo;
        if (resultVos.containsKey(instanceWarning.getMetaClassInstance().getId())) {
            vo = resultVos.get(instanceWarning.getMetaClassInstance().getId());
        } else {
            vo = new ValidatorResultVo();
            vo.setInstanceId(instanceWarning.getMetaClassInstance().getId());
            vo.setNamespace(container.queryStringProperty(
                    instanceWarning.getMetaClassInstance().getId(),
                    UMLDefinitionConstants.NamedElement_qualifiedName));
            vo.setAnnoations(new ArrayList<>());
            resultVos.put(instanceWarning.getMetaClassInstance().getId(), vo);
        }

        ValidatorAnnoation annotation = new ValidatorAnnoation();
        annotation.setSeverity(modelUsageSeverityEnum.getSeverity().value());
        annotation.setErrorType(modelUsageSeverityEnum.getErrorType());
        annotation.setAbbreviation(modelUsageSeverityEnum.abbreviation());
        annotation.setErrorMessage(modelUsageSeverityEnum.errorMessage());
        annotation.setWarningId(ignoreId);
        annotation.setIgnore(instanceWarning.getIgnore());
        vo.getAnnoations().add(annotation);
    }

    @NotNull
    public ModelResultVo reloadUsage(ProjectReloadDTO dto) {
        LogUtil.printSerializeOnlineLogs("reloadUsage -> dto: ", dto);
        final String projectId = dto.getProjectId();

        final UsageProject usageProject = usageProjectManager.getProject(dto.getUsageProjectId());
        if (usageProject == null) {
            log.error("使用项目不存在, projectId:{}", dto.getUsageProjectId());
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR);
        }

        ProjectDescription currentProjectDescription = new ProjectDescription("", projectId, "", projectId, null);
        List<ProjectDescription> useProjects = modelUsageService.queryUseProjects(projectId, currentProjectDescription);
        ProjectDescription usageProjectDescription = useProjects.get(0);
        if (Boolean.FALSE.equals(dto.getIsReplace())) {
            // 重载
            Optional<ProjectDescription> usageProjectDescriptionOp = useProjects.stream().filter(it -> it.getProjectId().equals(usageProject.getOrignalProjectId()))
                    .findFirst();
            if (!usageProjectDescriptionOp.isPresent()) {
                log.error("未找到可以重载的项目,重载项目id:{}", usageProject.getOrignalProjectId());
                log.error("当前项目的使用项目列表:{}", useProjects);
                throw AbortExecutionException.build(ErrorCode.SHARE_PROJECT_NOT_EXIST);
            }
            usageProjectDescription = usageProjectDescriptionOp.get();
        }

        //查询重载列表
        List<ProjectDescription> reloadUsageProjects = new ArrayList<>();
        reloadUsageProjects.add(usageProjectDescription);
        //开始重载
        ModelResultVo modelResultVo = new ModelResultVo();

        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        try {
            Set<String> existProjects = new HashSet<>();
            for (ProjectDescription childProject : reloadUsageProjects) {
                if (existProjects.contains(childProject.getProjectId())) {
                    continue;
                }

                existProjects.add(childProject.getProjectId());
                //2.重载项目
                reloadUsageProject(currentProjectDescription, usageProject, dto);
            }

            transactionService.commit(projectId);
            InstanceVoUtils.fillAddModelResultVo(modelResultVo, transaction);
            //引用项目自定义构造型图标丢失处理
            projectService.loadPrivateData(projectId, usageProject.getProjectSpecification());
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        } finally {
            // 清除命名规则缓存
            namingRuleCache.removeNamingRuleMap(projectId);
        }

        return modelResultVo;
    }


    private void reloadUsageProject(ProjectDescription currentProjectDes, UsageProject usageProject, ProjectReloadDTO dto) {
        LogUtil.printSerializeOnlineLogs("currentProjectDes: {}, usageProject: {}, dto: {}", currentProjectDes, usageProject, dto);
        ProjectDescription usageProjectDescription = new ProjectDescription(dto.getUsageProjectPath(),
                usageProject.getOrignalProjectId(), usageProject.getProjectName(), usageProject.getId(),
                usageProject.getVersion());

        //重载项目命令
        IAcrossCommand command = CommandFactory.createReloadShareProjectCommand(currentProjectDes,
                usageProjectDescription, dto.getDiagramModelIds(), dto.getOldUserProjectId(), dto.getIsReplace());
        try {
            commandExecutor.executesAcrossDataSource(command);
        } catch (CommandException e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }

        //更新共享包名称与icon
        List<ShareHangLocation> newSharingPackages =
                modelUsageService.querySharingPackages(usageProject.getId());
        final List<String> instanceIds = newSharingPackages.stream().map(ShareHangLocation::getInstanceId).collect(Collectors.toList());
        final Map<String, MetaClassInstance> instanceMap = internalUmlService.fetchInstances(instanceIds, usageProject.getId());
        final QueryPropertyForm form = internalUmlService
                .getQueryPropertyForm(new ArrayList<>(instanceMap.values()), UMLDefinitionConstants.NamedElement_name);
        final MofResultContainer container = internalUmlService.queryProperty(usageProject.getId(), form);
        List<ICommand> updateCommands = newSharingPackages.stream().map(it -> {
            MetaClassInstance usePackage = instanceMap.get(it.getInstanceId());
            if (usePackage != null) {
                String name = container.queryStringProperty(it.getInstanceId(), UMLDefinitionConstants.NamedElement_name);
                String icon = internalModelIconService.queryIcon(usageProject.getId(), usePackage);
                return CommandFactory.createUpdateUsePackageCommand(it.getInstanceId(), name, icon);
            }

            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());

        //更新项目版本与提示
        ICommand updateUseProjectCommand = CommandFactory.createUpdateUseProjectCommand(usageProject.getOrignalProjectId(),
                usageProject.getOrignalProjectId(), usageProject.getProjectPath(),
                usageProject.getProjectName(), usageProject.getVersion(), BooleanUtils.isTrue(dto.getPromptUpdate()) ? 1 : 0);
        updateCommands.add(updateUseProjectCommand);
        try {
            commandExecutor.executes(currentProjectDes.getProjectId(), updateCommands);
        } catch (CommandException e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }
        updateUsePackageLocation(dto.getUsagePackageParent(), currentProjectDes.getProjectId());
    }

    private void updateUsePackageLocation(List<UsagePackageVo> usagePackageParent, String projectId) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, usagePackageParent: {}", projectId, usagePackageParent);
        final Map<String, MetaClassInstance> locationMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(usagePackageParent)) {
            Set<String> parentIds = usagePackageParent.stream().map(UsagePackageVo::getUsedParent).collect(Collectors.toSet());
            Map<String, MetaClassInstance> parentMap = internalUmlService.fetchInstances(new ArrayList<>(parentIds), projectId);
            locationMap.putAll(usagePackageParent.stream().filter(usagePackageVo -> StringUtils.isNotEmpty(usagePackageVo.getUsedParent()))
                    .collect(Collectors.toMap(UsagePackageVo::getInstanceId,
                            usagePackageVo -> parentMap.get(usagePackageVo.getUsedParent()))));
        }

        List<UsePackage> usePackages = queryShareService.queryAllUsePackages(projectId);
        try {
            if (CollectionUtils.isNotEmpty(usePackages)) {
                String rootModel = Objects.requireNonNull(projectManager.getProject(projectId)).getRootModel();
                MetaClassInstance root = internalUmlService.fetchExistInstance(rootModel, projectId);
                List<UsePackage> updateUsePackage = usePackages.stream().map(usePackage -> {
                    String configurationHangLocation = usePackage.getConfigurationHangLocation();
                    MetaClassInstance parent = locationMap.get(usePackage.getInstanceId());
                    if (Objects.nonNull(parent) && locationMap.containsKey(usePackage.getInstanceId())) {
                        usePackage.setConfigurationHangLocation(parent.getId());
                        return usePackage;
                    } else if (StringUtils.isEmpty(configurationHangLocation)) {
                        usePackage.setConfigurationHangLocation(root.getId());
                        return usePackage;
                    } else {
                        return null;
                    }
                }).filter(Objects::nonNull).collect(Collectors.toList());

                internalProjectService.setGlobalWriteableState(projectId, true);
                saveShareService.updateUsePackages(projectId, updateUsePackage);
                List<ICommand> updateUsageOwnerCommands = updateUsePackage.stream().map(usePackage -> {
                    MetaClassInstance parent = locationMap.getOrDefault(usePackage.getInstanceId(), root);
                    if (parent == null) {
                        parent = root;
                    }
                    return umlService.createUpdateCommand(projectId, usePackage.getInstanceId(), UMLDefinitionConstants.Element_owner, parent);
                }).collect(Collectors.toList());
                commandExecutor.executes(projectId, updateUsageOwnerCommands);
                internalProjectService.setGlobalWriteableState(projectId, false);
            }
        } catch (CommandException e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }
    }


    /**
     * 填充使用项目重载链路
     *
     * @param projectId           当前项目id
     * @param usageProjectId      使用项目id
     * @param reloadUsageProjects 重载项目列表
     * @author xz
     * @date 2023/03/02 11:19
     */
    private void fillUsageProjectChain(@NotNull String projectId,
                                       @NotNull String usageProjectId,
                                       List<ProjectDescription> reloadUsageProjects) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, usageProjectId: {}, reloadUsageProjects: {}", projectId,
                usageProjectId, reloadUsageProjects);
        List<ProjectDescription> children = modelUsageService.queryUseProjects(projectId,
                new ProjectDescription("", usageProjectId, "", usageProjectId, null));
        reloadUsageProjects.addAll(children);
        for (ProjectDescription child : children) {
            fillUsageProjectChain(projectId, child.getProjectId(), reloadUsageProjects);
        }
    }

    @NotNull
    public ModelResultVo deleteUsage(ShareDeleteDTO dto) {
        LogUtil.printSerializeOnlineLogs("deleteUsage -> dto: ", dto);
        final String projectId = dto.getProjectId();
        int lastIndex = dto.getCancelShareProjectId().lastIndexOf("_");
        final String cancelShareProjectId = lastIndex != -1 ? dto.getCancelShareProjectId().substring(0, lastIndex) : dto.getCancelShareProjectId();
        List<ProjectDescription> useProjects = modelUsageService.queryUseProjects(projectId,
                new ProjectDescription("", projectId, "", projectId, null));
        if (useProjects.stream().noneMatch(it -> Objects.equals(it.getProjectId(), cancelShareProjectId))) {
            log.error("未找到引用的使用项目:{}", useProjects);
            throw AbortExecutionException.build(ErrorCode.SHARE_PROJECT_NOT_EXIST);
        }

        IAcrossCommand command = CommandFactory.createCancelUseShareProjectCommand(projectId,
                cancelShareProjectId);
        ModelResultVo modelResultVo = new ModelResultVo();

        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        try {
            commandExecutor.executesAcrossDataSource(command);
            transactionService.commit(projectId);
            InstanceVoUtils.fillAddModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }

        return modelResultVo;
    }

    @NotNull
    public List<PackageShareVo> querySharePackageList(String projectId) {
        LogUtil.printOnlineLogs("querySharePackageList -> projectId: ", projectId);
        List<ShareHangLocation> sharePackageInfos = modelUsageService.querySharingPackages(projectId);

        List<MetaClassInstance> sharePackages = internalUmlService.fetchInstanceByIds(
                sharePackageInfos.stream().map(ShareHangLocation::getInstanceId).collect(Collectors.toList()), projectId);

        QueryPropertyForm sharePackagesForm = internalUmlService.getQueryPropertyForm(
                sharePackages,
                Stream.of(UMLDefinitionConstants.NamedElement_name,
                        UMLDefinitionConstants.NamedElement_qualifiedName).collect(Collectors.toList()));
        MofResultContainer sharePackagesResult = internalUmlService.queryProperty(projectId, sharePackagesForm);

        Map<String, String> iconMap = modelPropertyInfoService.queryIconBatch(projectId, sharePackages);

        return sharePackageInfos.stream().map(it -> {
            final String instanceId = it.getInstanceId();
            PackageShareVo vo = new PackageShareVo();
            vo.setInstanceId(instanceId);
            vo.setType(it.getShareType().name());
            vo.setExpectParent(it.getExpectedHangLocation());
            vo.setName(sharePackagesResult.queryStringProperty(instanceId, UMLDefinitionConstants.NamedElement_name));
            vo.setIcon(iconMap.get(instanceId));
            vo.setNamespace(validationService.fetchNamespace(
                    sharePackagesResult.queryStringProperty(instanceId, UMLDefinitionConstants.NamedElement_qualifiedName)));
            return vo;
        }).collect(Collectors.toList());
    }

    @NotNull
    public UsageProjectNodeVo queryUsageProjectTree(String projectId) {
        LogUtil.printOnlineLogs("queryUsageProjectTree -> projectId: ", projectId);
        Project project = projectManager.getValidProject(projectId);
        ProjectDescription projectDes = new ProjectDescription("", project.getId(), "当前项目", project.getId(), null);
        return getUsageProjectNodeVo(projectId, projectDes);
    }

    public UsageProjectNodeVo queryUsageProjectTreeByUsageProjectId(String projectId) {
        LogUtil.printOnlineLogs("queryUsageProjectTree -> projectId: ", projectId);
        UsageProject project = usageProjectManager.getProject(projectId);
        if (Objects.isNull(project)) {
            log.error("项目不存在,projectId:{}", projectId);
            throw AbortExecutionException.build(ErrorCode.PROJECT_NOT_FOUND);
        }
        ProjectDescription projectDes = new ProjectDescription("", project.getOrignalProjectId(), "当前项目", project.getId(), null);
        return getUsageProjectNodeVo(projectId, projectDes);
    }

    @NotNull
    private UsageProjectNodeVo getUsageProjectNodeVo(String projectId, ProjectDescription projectDes) {
        Map<String, UseProject> useProjectDOS = modelUsageService.queryAllUseProjectDOS(projectId).stream()
                .collect(Collectors.toMap(it -> it.getUsableProject().getProjectId(), it -> it));
        UsageProjectNodeVo nodeVo = makeUsageProjectNodeVo(projectDes, useProjectDOS);
        List<ProjectDescription> child = modelUsageService.queryUseProjects(projectId, projectDes);

        nodeVo.setChild(child.stream().map(it -> createUsageProjectNodeVo(projectId, it, useProjectDOS,
                new HashSet<>())).collect(Collectors.toList()));
        return nodeVo;
    }

    private UsageProjectNodeVo makeUsageProjectNodeVo(ProjectDescription projectDes, Map<String, UseProject> useProjectDOS) {
        UsageProjectNodeVo nodeVo = new UsageProjectNodeVo();
        nodeVo.setProjectId(projectDes.getProjectId());
        nodeVo.setProjectName(projectDes.getProjectName());
        nodeVo.setShareProjectPath(projectDes.getProjectPath());
        nodeVo.setVersionId(projectDes.getVersionId());
        UseProject projectDO = useProjectDOS.get(projectDes.getProjectId());
        if (projectDO != null) {
            nodeVo.setPromptUpdate(Objects.equals(projectDO.getPromptUpdate(), 1));
        }
        return nodeVo;
    }

    @NotNull
    private UsageProjectNodeVo createUsageProjectNodeVo(String projectId,
                                                        ProjectDescription parentNode,
                                                        Map<String, UseProject> useProjectDOS,
                                                        Set<String> parentNodeProjectIds) {
        LogUtil.printSerializeOnlineLogs("projectId: {}, parentNode: {}, useProjectDOS: {}, parentNodeProjectIds: {}",
                projectId, parentNode, useProjectDOS, parentNodeProjectIds);
        UsageProjectNodeVo nodeVo = makeUsageProjectNodeVo(parentNode, useProjectDOS);
        if (!parentNodeProjectIds.contains(parentNode.getProjectId())) {
            parentNodeProjectIds.add(parentNode.getProjectId());
        } else {
            return nodeVo;
        }
        List<ProjectDescription> child = modelUsageService.queryUseProjects(projectId, parentNode);
        if (CollectionUtils.isNotEmpty(child)) {
            nodeVo.setChild(child.stream().map(it -> createUsageProjectNodeVo(projectId, it, useProjectDOS,
                    parentNodeProjectIds)).collect(Collectors.toList()));
        }

        return nodeVo;
    }


    @NotNull
    public List<UsagePackageVo> queryUsagePackageByProject(String projectId, String usageProjectId) {
        LogUtil.printOnlineLogs("projectId: {}, usageProjectId： {}", projectId, usageProjectId);
        ProjectDescription projectDes = new ProjectDescription("", projectId, "当前项目", projectId, null);
        Set<String> projectIds = modelUsageService.queryUseProjects(projectId, projectDes).stream()
                .map(ProjectDescription::getProjectId)
                .collect(Collectors.toSet());
        if (usageProjectId == null) {
            List<UsePackage> usePackageDOS = modelUsageService.queryAllUsePackages(projectId);
            Map<String, UseProject> shareUseProjectDOMap =
                    modelUsageService.queryAllUseProjectDOS(projectId).stream().collect(Collectors.toMap(it -> it.getUsableProject().getProjectId(),
                            it -> it));
            return usePackageDOS.stream().map(it -> {
                UsagePackageVo vo = new UsagePackageVo();
                vo.setInstanceId(it.getInstanceId());
                vo.setExpectParent(it.getExpectedHangLocation());
                vo.setUsedParent(it.getConfigurationHangLocation());
                vo.setName(it.getName());
                vo.setIcon(it.getIcon());
                if (shareUseProjectDOMap.containsKey(it.getUseProject().getProjectId())) {
                    UseProject useProjectDO = shareUseProjectDOMap.get(it.getUseProject().getProjectId());
                    vo.setUsageProjectId(useProjectDO.getUsableProject().getProjectId());
                    vo.setUsageProjectName(useProjectDO.getUsableProject().getProjectName());
                    vo.setUsageProjectPath(useProjectDO.getUsableProject().getProjectPath());
                }

                vo.setDirectUsage(projectIds.contains(it.getUseProject().getProjectId()));

                return vo;
            }).collect(Collectors.toList());
        } else {
            ProjectDescription projectDescription = new ProjectDescription("", usageProjectId, "",
                    usageProjectId, null);
            List<UsePackageDescription> result = modelUsageService.queryUsePackages(projectId, projectDescription);
            return result.stream().map(it -> {
                UsagePackageVo vo = new UsagePackageVo();
                vo.setInstanceId(it.getMetaClassInstance().getId());
                vo.setExpectParent(it.getExpectedHangLocation());
                vo.setUsedParent(it.getConfigurationHangLocation());
                vo.setName(it.getName());
                vo.setIcon(it.getIcon());
                return vo;
            }).collect(Collectors.toList());
        }
    }

    /**
     * 关闭使用项目
     *
     * @param usageProjectId
     * @return void
     * @author xz
     * @date 2023/02/21 18:08
     */
    public void close(String usageProjectId) {
        LogUtil.printOnlineLogs("usageProjectId: ", usageProjectId);
        usageProjectManager.clear(usageProjectId);
    }

    /**
     * 判断是否为有效项目
     *
     * @param projectId
     * @param usageProjectId
     * @return com.huawang.mdesign.model.service.vo.IllegalVo
     * @author xz
     * @date 2023/03/02 18:18
     */
    @NotNull
    public IllegalVo isValidUsageProject(String projectId, String usageProjectId, Boolean excludeSelf) {
        LogUtil.printOnlineLogs("projectId: {}, usageProjectId: {}, excludeSelf: {}", projectId, usageProjectId, excludeSelf);
        IllegalVo isRepeat = new IllegalVo();
        List<ProjectDescription> userProjects = modelUsageService.queryUseProjects(projectId,
                new ProjectDescription("", projectId, "", projectId, null));
        boolean isRepeatProject = userProjects.stream().anyMatch(it -> {
            if (Boolean.TRUE.equals(excludeSelf)) {
                return !Objects.equals(it.getProjectId(), usageProjectId) && Objects.equals(it.getProjectId(),
                        usageProjectId);
            } else {
                return Objects.equals(it.getProjectId(), usageProjectId);
            }
        });

        if (isRepeatProject) {
            isRepeat.setValidType(ErrorCode.USAGE_PROJECT_REPEAT.name().toLowerCase());
            isRepeat.setValidResult(Boolean.FALSE);
            return isRepeat;
        }

        return isRepeat;
    }

    @NotNull
    public ModelResultVo clearReferencing(ClearReferenceDTO dto) {
        LogUtil.printSerializeOnlineLogs("clearReferencing -> dto: ", dto);
        final String projectId = dto.getProjectId();
        ICommand command = CommandFactory.createClearReferencingCommand(dto.getInstanceId(),
                dto.getPropertyKey(), internalUmlService.fetchExistInstance(dto.getValue(), projectId));
        return executeCommand(projectId, command);
    }

    @NotNull
    public ModelResultVo clearReferenced(ClearReferencedDTO dto) {
        LogUtil.printSerializeOnlineLogs("clearReferenced -> dto: ", dto);
        final String projectId = dto.getProjectId();
        ICommand command = CommandFactory.createClearReferencedCommand(dto.getInstanceId());
        return executeCommand(projectId, command);
    }

    /**
     * 执行mof命令
     *
     * @param projectId
     * @param command
     * @return
     */
    @NotNull
    private ModelResultVo executeCommand(String projectId, ICommand command) {
        LogUtil.printOnlineLogs("executeCommand -> projectId: ", projectId);
        return executeCommands(projectId, Collections.singletonList(command));
    }

    @NotNull
    private ModelResultVo executeCommands(String projectId, List<ICommand> commands) {
        LogUtil.printOnlineLogs("executeCommands -> projectId: ", projectId);
        ModelResultVo modelResultVo = new ModelResultVo();

        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        try {
            commandExecutor.executes(projectId, commands);
            transactionService.commit(projectId);
            InstanceVoUtils.fillAddModelResultVo(modelResultVo, transaction);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }
        return modelResultVo;
    }

    @NotNull
    public ModelResultVo changeReference(ChangeReferenceDTO dto) {
        LogUtil.printSerializeOnlineLogs("changeReference -> dto: ", dto);
        final String projectId = dto.getProjectId();
        ICommand command = CommandFactory.createChangeUseElementCommand(dto.getInstanceId(),
                dto.getPropertyKey(), internalUmlService.fetchExistInstance(dto.getSourceValue(), projectId),
                internalUmlService.fetchExistInstance(dto.getTargetValue(), projectId));
        return executeCommand(projectId, command);
    }

    @NotNull
    public ModelResultVo changeReferenced(ChangeReferencedDTO dto) {
        LogUtil.printSerializeOnlineLogs("changeReferenced -> dto: ", dto);
        final String projectId = dto.getProjectId();
        ICommand command = CommandFactory.createChangeUsedElementCommand(dto.getSourceId(),
                dto.getTargetId());
        return executeCommand(projectId, command);
    }

    public void ignoreWaring(IgnoreWarningDTO dto) {
        LogUtil.printSerializeOnlineLogs("ignoreWaring -> dto: ", dto);
        ICommand command;
        if (ModelShareSeverityEnum.isValidEnum(dto.getWarningType())) {
            if (BooleanUtils.isTrue(dto.getIgnore())) {
                command = CommandFactory.createAddShareIgnoreCommand(dto.getWarningId());
            } else {
                command = CommandFactory.createRemoveShareIgnoreCommand(dto.getWarningId());
            }
        } else {
            if (BooleanUtils.isTrue(dto.getIgnore())) {
                command = CommandFactory.createAddUseIgnoreCommand(dto.getWarningId());
            } else {
                command = CommandFactory.createRemoveUseIgnoreCommand(dto.getWarningId());
            }
        }

        try {
            commandExecutor.execute(dto.getProjectId(), command);
        } catch (CommandException e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }
    }

    @NotNull
    public List<String> queryUsageElement(String projectId) {
        LogUtil.printOnlineLogs("queryUsageElement -> projectId: ", projectId);
        UseWarning usingWarnings = modelUsageService.getUseWarning(projectId);
        return usingWarnings.getUseInstances().values().stream().map(it -> it.getMetaClassInstance().getId()).collect(Collectors.toList());
    }

    @NotNull
    public UseElementGroupVo queryUseElement(String projectId) {
        LogUtil.printOnlineLogs("queryUseElement -> projectId: ", projectId);
        List<UseElement> dos = queryShareService.queryAllUseElements(projectId);
        Map<UseType, List<UseElement>> useElementMap =
                dos.stream().collect(Collectors.groupingBy(UseElement::getUseType));
        UseElementGroupVo group = new UseElementGroupVo();
        group.setUseElements(getUseElementFromMap(useElementMap, UseType.USE_ELEMENT));
        group.setRecoverElements(getUseElementFromMap(useElementMap, UseType.RECOVER));
        group.setProxyElements(getUseElementFromMap(useElementMap, UseType.PROXY));
        return group;
    }

    @NotNull
    private static List<String> getUseElementFromMap(Map<UseType, List<UseElement>> useElementMap, UseType type) {
        LogUtil.printSerializeOnlineLogs("useElementMap: {}, type: {}", useElementMap, type);
        return useElementMap.getOrDefault(type, new ArrayList<>()).stream().map(UseElement::getInstanceId).collect(Collectors.toList());
    }

    @NotNull
    public UsageModelInfoVo queryUsageModelInfo(String projectId, String instanceId) {
        LogUtil.printOnlineLogs("projectId: {}, instanceId: {}", projectId, instanceId);
        ProjectDescription des = modelUsageService.queryUseInstanceOwningProject(projectId, instanceId);
        UsageModelInfoVo vo = new UsageModelInfoVo();
        if (des != null) {
            vo.setUsageProjectId(des.getProjectId());
            vo.setUsageProjectPath(des.getProjectPath());
            vo.setUsageProjectName(des.getProjectName());
            vo.setVersionId(des.getVersionId());
        }
        return vo;
    }

    @NotNull
    public AffectProjectVo queryAffectProjects(String projectId, String usageProjectId) {
        LogUtil.printOnlineLogs("projectId: {}, usageProjectId: {}", projectId, usageProjectId);
        AffectProjects affectProjects = modelUsageService.queryAffectProjectsByDeleting(projectId,
                usageProjectId);
        AffectProjectVo vo = new AffectProjectVo();
        if (Objects.nonNull(affectProjects)) {
            vo.setIndirectProjects(affectProjects.getSubsequentDeletingProjectList().stream()
                    .map(ProjectDescription::getProjectName).collect(Collectors.toList()));
        }
        return vo;
    }

    @NotNull
    public List<String> queryAllShareDiagram(String usageProjectId) {
        LogUtil.printOnlineLogs("usageProjectId: ", usageProjectId);
        List<ShareHangLocation> shareHangLocations = modelUsageService.querySharingPackages(usageProjectId);
        return shareHangLocations.stream()
                .flatMap(it -> internalDiagramService.queryChildDiagram(usageProjectId, it.getInstanceId()).stream())
                .collect(Collectors.toList());

    }

    /**
     * 更新使用项目路径
     *
     * @param dto
     * @return void
     * @author xz
     * @date 2023/09/25 11:16
     */
    public void updateUseProjectPath(UpdateUsageProjectPathDTO dto) {
        LogUtil.printSerializeOnlineLogs("updateUseProjectPath -> dto: ", dto);
        List<ProjectReflectionDTO> projectIdMap = dto.getProjectIdMap();
        String projectId = dto.getProjectId();
        String updatingProjectId = dto.getUserProjectId();
        String oldProjectId = dto.getUpdatingProjectId();
        String projectPath = dto.getProjectPath();
        String defaultProjectId = null;
        for (ProjectReflectionDTO projectReflectionDTO : projectIdMap) {
            if (Objects.equals(projectReflectionDTO.getOldProjectId(), oldProjectId)) {
                defaultProjectId = projectReflectionDTO.getNewProjectId();
            }
        }
        if (Objects.isNull(defaultProjectId) || Objects.isNull(oldProjectId)) {
            return;
        }
        IAcrossCommand command = CommandFactory.createUpdateUsageProjectIdCommand(projectId,
                projectId, defaultProjectId, oldProjectId, projectPath);

        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        //更新主项目项目中use_project表
        try {
            transactionService.commit(projectId);
            commandExecutor.executesAcrossDataSource(command);
        } catch (CommandException e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.USAGE_PROJECT_UPDATE_ERROR, e);
        }
        //更新当前项目中use_project表
        LocalTransaction transaction1 = transactionService.createTransaction(updatingProjectId, PROJECT_USAGE);
        for (ProjectReflectionDTO projectReflectionDTO : projectIdMap) {
            IAcrossCommand updateUsageProjectIdCommand = CommandFactory.createUpdateUsageProjectIdCommand(projectId,
                    updatingProjectId, projectReflectionDTO.getNewProjectId(),
                    projectReflectionDTO.getOldProjectId(), null);
            try {
                commandExecutor.executesAcrossDataSource(updateUsageProjectIdCommand);
            } catch (CommandException e) {
                throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
            }
        }
        try {
            transactionService.commit(updatingProjectId);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction1);
            throw AbortExecutionException.build(ErrorCode.USAGE_PROJECT_UPDATE_ERROR, e);
        }
    }

    public void updateUseProject(UpdateUseProjectDTO dto) {
        LogUtil.printSerializeOnlineLogs("updateUseProject -> dto: ", dto);
        final String projectId = dto.getProjectId();
        UseProject useProjectDO = modelUsageService.queryUseProjectByProjectId(projectId, dto.getUseProjectId());
        if (useProjectDO == null) {
            log.error("使用项目id不存在:{}", dto.getUseProjectId());
            throw AbortExecutionException.build(ErrorCode.SHARE_PROJECT_NOT_EXIST);
        }
        ICommand command = CommandFactory.createUpdateUseProjectCommand(dto.getUseProjectId(),
                useProjectDO.getUsableProject().getProjectId(), useProjectDO.getUsableProject().getProjectPath(),
                useProjectDO.getUsableProject().getProjectName(),
                null,
                BooleanUtils.isTrue(dto.getPromptUpdate()) ? 1 : 0);

        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        try {
            commandExecutor.executes(projectId, Stream.of(command).collect(Collectors.toList()));
            transactionService.commit(projectId);
        } catch (TransactionNotExistingException | LocalTransactionNotStartException e) {
            throw AbortExecutionException.build(ErrorCode.TRANSACTION_ERROR, e);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.USAGE_PROJECT_UPDATE_ERROR, e);
        }
    }

    @NotNull
    public ModelResultVo missProject(MissProjectDTO dto) {
        LogUtil.printSerializeOnlineLogs("missProject -> dto: ", dto);
        final String projectId = dto.getProjectId();
        ICommand command = CommandFactory.createTransformToProxyCommand(dto.getMissProjectId());
        return executeCommands(projectId, Stream.of(command).collect(Collectors.toList()));
    }

    @NotNull
    public List<String> queryAutoShareProfile(String projectId) {
        LogUtil.printOnlineLogs("queryAutoShareProfile -> projectId: ", projectId);
        List<ShareHangLocation> sharePackages = modelUsageService.querySharingPackages(projectId);
        return sharePackages.stream().filter(it -> it.getShareType().equals(ShareType.PASSIVE_SHARE_PACKAGE))
                .filter(it -> {
                    MetaClassInstance instance = internalUmlService.fetchInstance(it.getInstanceId(), projectId);
                    return instance != null && internalUmlService.checkInstanceType(projectId, instance,
                            UMLDefinitionConstants.Profile)
                            && BusinessJudgeService.isImportFromProfile(instance);
                }).map(ShareHangLocation::getInstanceId).collect(Collectors.toList());
    }

    public void updateProjectId(UpdateProjectIdDTO[] updateProjectIdDTOs) {
        LogUtil.printSerializeOnlineLogs("updateProjectIdDTOs: ", updateProjectIdDTOs);
        if (updateProjectIdDTOs.length == 0) {
            return;
        }
        String projectId = updateProjectIdDTOs[0].getProjectId();

        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_USAGE);
        for (UpdateProjectIdDTO updateProjectIdDTO : updateProjectIdDTOs) {
            String updatingProjectId = updateProjectIdDTO.getNewProjectId();
            String oldProjectId = updateProjectIdDTO.getOldProjectId();
            String projectPath = updateProjectIdDTO.getProjectPath();
            IAcrossCommand command = CommandFactory.createUpdateUsageProjectIdCommand(projectId,
                    projectId, updatingProjectId, oldProjectId, projectPath);
            //更新主项目项目中use_project表
            try {
                commandExecutor.executesAcrossDataSource(command);
            } catch (CommandException e) {
                throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
            }
        }
        try {
            transactionService.commit(projectId);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.USAGE_PROJECT_UPDATE_ERROR, e);
        }
    }

    public void updateUsageProjectId(UpdateUsageProjectPathDTO dto) {
        LogUtil.printSerializeOnlineLogs("updateUsageProjectId -> dto: ", dto);
        List<ProjectReflectionDTO> projectIdMap = dto.getProjectIdMap();
        String projectId = dto.getProjectId();
        String updatingProjectId = dto.getUserProjectId();
        String oldProjectId = dto.getUpdatingProjectId();
        String defaultProjectId = null;
        for (ProjectReflectionDTO projectReflectionDTO : projectIdMap) {
            if (Objects.equals(projectReflectionDTO.getOldProjectId(), oldProjectId)) {
                defaultProjectId = projectReflectionDTO.getNewProjectId();
            }
        }
        if (Objects.isNull(defaultProjectId) || Objects.isNull(oldProjectId)) {
            return;
        }
        // 检查是否有交叉引用的情况，如果有，完善use_project表
        List<UseProject> mainShareUseProjectDOS = modelUsageService.queryAllUseProjectDOS(projectId);
        List<String> mainUseProjectIds = mainShareUseProjectDOS.stream()
                .map(it -> it.getUsableProject().getProjectId()).collect(Collectors.toList());
        Map<String, UseProject> shareUseProjectMap = mainShareUseProjectDOS.stream()
                .collect(Collectors.toMap(it -> it.getUsableProject().getProjectId(), it -> it, (a, b) -> a));
        List<UseProject> useProjectDOS = modelUsageService.queryAllUseProjectDOS(updatingProjectId);
        final List<ICommand> commandList = new ArrayList<>();
        final String tempPreProjectId = defaultProjectId;
        useProjectDOS.forEach(it -> {
            String useProjectId = it.getUsableProject().getProjectId();
            if (mainUseProjectIds.contains(useProjectId)) {
                UseProject shareUseProjectDO = shareUseProjectMap.get(useProjectId);
                String preProjectId = shareUseProjectDO.getPreProject().getProjectId();
                if (!preProjectId.contains(useProjectId)) {
                    String newPreProjectId = preProjectId + "," + tempPreProjectId;
                    ICommand updateUseProjectCommand = CommandFactory.createUpdateUseProjectCommand(
                            shareUseProjectDO.getUsableProject().getProjectId(),
                            shareUseProjectDO.getUsableProject().getProjectPath(),
                            shareUseProjectDO.getUsableProject().getProjectId(),
                            shareUseProjectDO.getUsableProject().getProjectName(),
                            shareUseProjectDO.getPreProject().getProjectPath(),
                            newPreProjectId,
                            shareUseProjectDO.getPreProject().getProjectName());
                    commandList.add(updateUseProjectCommand);
                }
            }
        });
        try {
            commandExecutor.executes(projectId, commandList);
        } catch (CommandException e) {
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
        }
        //更新当前项目中use_project表
        LocalTransaction transaction = transactionService.createTransaction(updatingProjectId, PROJECT_USAGE);
        for (ProjectReflectionDTO projectReflectionDTO : projectIdMap) {
            IAcrossCommand updateUsageProjectIdCommand = CommandFactory.createUpdateUsageProjectIdCommand(projectId,
                    updatingProjectId, projectReflectionDTO.getNewProjectId(),
                    projectReflectionDTO.getOldProjectId(), null);
            try {
                commandExecutor.executesAcrossDataSource(updateUsageProjectIdCommand);
            } catch (CommandException e) {
                throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR, e);
            }
        }
        try {
            transactionService.commit(updatingProjectId);
        } catch (Exception e) {
            transactionService.rollBack(updatingProjectId, transaction);
            throw AbortExecutionException.build(ErrorCode.USAGE_PROJECT_UPDATE_ERROR, e);
        }
    }

    public void updateUseProjectToSaveAs(String currentProjectId, String saveAsProjectId) {
        LogUtil.printOnlineLogs("currentProjectId: {}, saveAsProjectId: {}", currentProjectId, saveAsProjectId);
        saveAsProjectMap.put(saveAsProjectId, currentProjectId);
    }

    /**
     * 获取设置为当前项目元素的项目的子共享项目
     *
     * @param targetProjectId    目标项目id
     * @param useProjectIdMap    当前直接使用的项目id集合
     * @param usageProjectNodeVo 项目树节点
     * @return
     */
    private List<UsageProjectNodeVo> lookUpNestChildProjectId(String targetProjectId, Map<String, UseProject> useProjectIdMap,
                                                              Map<String, String> containMap,
                                                              UsageProjectNodeVo usageProjectNodeVo) {

        if (targetProjectId.equals(usageProjectNodeVo.getProjectId())) {
            if (CollectionUtils.isEmpty(usageProjectNodeVo.getChild())) {
                return Collections.emptyList();
            }
            return usageProjectNodeVo.getChild().stream().filter(e -> !containMap.containsKey(e.getProjectId())).
                    collect(Collectors.toList());
        }
        List<UsageProjectNodeVo> child = usageProjectNodeVo.getChild();
        if (CollectionUtils.isNotEmpty(child)) {
            for (UsageProjectNodeVo childVo : child) {
                String projectId = childVo.getProjectId();
                if (useProjectIdMap.containsKey(projectId)) {
                    containMap.put(projectId, projectId);
                }
            }
            for (UsageProjectNodeVo childVo : child) {
                List<UsageProjectNodeVo> usageProjectNodeVos = lookUpNestChildProjectId(targetProjectId, useProjectIdMap, containMap, childVo);
                if (CollectionUtils.isNotEmpty(usageProjectNodeVos)) {
                    return usageProjectNodeVos;
                }
            }
        }

        return Collections.emptyList();
    }

    public void setAsElement(SetAsOwnElementDTO dto) {
        String projectId = dto.getProjectId();
        final UsageProject usageProject = usageProjectManager.getProject(dto.getUsageProjectId());
        if (usageProject == null) {
            log.error("使用项目不存在, projectId:{}", dto.getUsageProjectId());
            throw AbortExecutionException.build(ErrorCode.PROJECT_USAGE_ERROR);
        }
        String usageProjectId = usageProject.getId();
        LogUtil.printOnlineLogs("projectId: {}, usageProjectId: {}", projectId, usageProjectId);
        //嵌套其他共享包
        Map<String, UseProject> useProjectIdMap = queryShareService.queryAllUseProjects(projectId).stream().
                collect(Collectors.toMap(e -> e.getUsableProject().getProjectId(), e -> e, (a, b) -> a));
        //项目树
        UsageProjectNodeVo usageProjectNodeVo = queryUsageProjectTree(projectId);
        //判断循环使用项目 (不允许循环使用)
        UsageProjectNodeVo childNodeTreeVo = queryUsageProjectTreeByUsageProjectId(usageProjectId);
        if (checkLoopReference(projectId, childNodeTreeVo)) {
            throw AbortExecutionException.build(ErrorCode.EXIST_LOOP_REFERENCE);
        }
        checkNestReference(projectId, usageProject.getOrignalProjectId(), useProjectIdMap);

        //拿到嵌套的共享包的项目id
        List<UsageProjectNodeVo> needSetUsageProjectIds = lookUpNestChildProjectId(usageProject.getOrignalProjectId(), useProjectIdMap, new HashMap<>(), usageProjectNodeVo);
        List<UseProject> useProjects = new ArrayList<>();
        //未使用嵌套共享项目下的所有包（a->b,b->c、d,a未使用c、d）
        List<ShareElement> allList = getShareElements(projectId, usageProjectId, needSetUsageProjectIds, useProjects, useProjectIdMap);

        LocalTransaction transaction = transactionService.createTransaction(projectId, PROJECT_PRIVATIZATION);
        try {
            Set<String> elementIds = modelUsageService.removeAllUseProjectDataByUseProjectIds(projectId, usageProject.getOrignalProjectId());
            //elementid需要过滤出设置为使用项目的元素，避免将使用项目元素也设置成可编辑
            Set<String> needFilterElementIds = insertUseSheet(projectId, useProjects, allList, elementIds);
            elementIds = elementIds.stream().filter(e -> !needFilterElementIds.contains(e)).collect(Collectors.toSet());
            //已有的元素，修改为可编辑
            internalUmlService.setIsNotReadOnly(projectId, new ArrayList<>(elementIds));
            transactionService.commit(projectId);
        } catch (Exception e) {
            transactionService.rollBack(projectId, transaction);
            throw AbortExecutionException.build(ErrorCode.USAGE_PROJECT_UPDATE_ERROR, e);
        }


    }

    private void checkNestReference(String maninProjectId, String usageProjectId, Map<String, UseProject> useProjectIdMap) {
        if (useProjectIdMap.containsKey(usageProjectId)) {
            UseProject useProject = useProjectIdMap.get(usageProjectId);
            String[] split = useProject.getPreProject().getProjectId().split(",");
            if (split.length > 1) {
                List<String> collect = Arrays.stream(split).filter(e -> !maninProjectId.equals(e)).collect(Collectors.toList());
                StringBuilder sb = new StringBuilder();
                collect.forEach(id -> {
                    if (useProjectIdMap.containsKey(id)) {
                        if (sb.length() == 0) {
                            sb.append(useProjectIdMap.get(id).getUsableProject().getProjectName());
                        } else {
                            sb.append(",").append(useProjectIdMap.get(id).getUsableProject().getProjectName());
                        }
                    }
                });
                ErrorCode errorCode = ErrorCode.EXIST_NEST_REFERENCE;
                throw AbortExecutionException.build(errorCode.getCode(),
                        String.format(errorCode.getMessage(), sb.toString()),
                        errorCode.getTitle());
            }

        }
    }


    private boolean checkLoopReference(String mainProject, UsageProjectNodeVo childNodeTreeVo) {
        if (Objects.isNull(childNodeTreeVo)) {
            return false;
        }
        if (mainProject.equals(childNodeTreeVo.getProjectId())) {
            return true;
        }
        if (CollectionUtils.isNotEmpty(childNodeTreeVo.getChild())) {
            for (UsageProjectNodeVo usageProjectNodeVo : childNodeTreeVo.getChild()) {
                checkLoopReference(mainProject, usageProjectNodeVo);
            }
        }
        return false;
    }


    private Set<String> insertUseSheet(String projectId, List<UseProject> useProjects, List<ShareElement> allList, Set<String> elementIds) {
        if (CollectionUtils.isNotEmpty(allList)) {
            List<ShareElement> hadElements = allList.stream().filter(e -> elementIds.contains(e.getElementId())).collect(Collectors.toList());
            List<UseElement> useElements = hadElements.stream().flatMap(e ->
                    e.getChildren().stream().map(c -> UseElement.builder().
                            useProject(e.getProjectId()).instanceId(c).useType(UseType.USE_ELEMENT).build())
            ).collect(Collectors.toList());
            List<UsePackage> usePackageList = hadElements.stream().map(
                    e -> UsePackage.builder().
                            useProject(e.getProject()).
                            name(e.getName()).
                            expectedHangLocation(e.getExpectedHangPosition()).
                            configurationHangLocation(e.getConfigurationHangLocation()).icon(e.getIcon()).instanceId(e.getElementId()).build()
            ).collect(Collectors.toList());
            //变成直接使用项目的，只记录在表中，不额外复制模型元素
            saveShareService.addUseElements(projectId, useElements);
            saveShareService.addUsePackages(projectId, usePackageList);
            saveShareService.addUseProjects(projectId, useProjects);
            return allList.stream().flatMap(e -> e.getChildren().stream()).collect(Collectors.toSet());
        }
        return Collections.emptySet();
    }

    @NotNull
    private List<ShareElement> getShareElements(String mainProjectId,
                                                String usageProjectId,
                                                List<UsageProjectNodeVo> needSetUsageProjectIds,
                                                List<UseProject> useProjects,
                                                Map<String, UseProject> useProjectIdMap) {
        List<ShareElement> allList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(needSetUsageProjectIds)) {
            //查询c、d的共享包以及包下模型元素
            //不添加具体模型元素，仅将c中的共享包、共享元素数据插入use表中
            com.huawang.business.data.share.entity.Project project = new com.huawang.business.data.share.entity.Project(mainProjectId, "", "");
            for (UsageProjectNodeVo usageProjectNode : needSetUsageProjectIds) {
                String needSetUsageProjectId = usageProjectNode.getProjectId();
                if (useProjectIdMap.containsKey(needSetUsageProjectId)) {
                    UseProject useProject = useProjectIdMap.get(needSetUsageProjectId);
                    useProjects.add(
                            UseProject.builder().
                            usableProject(useProject.getUsableProject()).
                            preProject(project).
                            versionId(1).
                            promptUpdate(0).
                            build());
                    allList.addAll(modelUsageService.queryAllShareElementByProjectId(usageProjectId,
                            needSetUsageProjectId, useProject.getUsableProject()));
                }
            }
        }
        return allList;
    }
}
